![]() Acrobat file (135K) |
![]() ClarisWorks 4 file (39K) |
![]() not available yet |
Technote 1063 | September 1996 |
Updated by Quinn "The Eskimo!"
Apple Developer Technical Support
28 March 1997
This Note highlights the usage of two fields -- tmReserved and tmWakeUp -- that might be unclear after reading the chapter "Time Manager" in Inside Macintosh: Processes.
This Note is intended for all developers who want to do time measurement using the Time Manager routines.theTMTask.tmWakeUp = theTMTask.tmReserved = 0; InsXTime((QElemPtr)&theTMTask); PrimeTime((QElemPtr)&theTMTask, 2000);If you do want to do some time measurement, then you have to call RmvTime to get the current value of tmCount, which leads later to a new call to InsXTime, and a call to PrimeTime with a 0 delay which has a special meaning in that case. Although it appears, after much reading, rather clear that you leave the current value of tmWakeUp untouched in the TMTask structure, you can't be sure what to do about the value of tmReserved.
The truth is that prior to October, 1992 (System Software 7.1), you didn't care, but it's more of a concern now, since Apple slightly modified the behavior of the Time Manager to deal with performance issues.
If you leave tmReserved untouched, then, after 127 calls to the following code:
RmvTime((QElemPtr)&theTMTask); remaining = theTMTask.tmCount; InsXTime((QElemPtr)&theTMTask); PrimeTime((QElemPtr)&theTMTask, 0);for some good but can't-be-disclosed reason, your extended time task is converted into a non-extended time task which, being waked up with a 0 delay PrimeTime (which has no special meaning for a non-extended time task), will suddenly be called and called again -- more frequently than it should be.
So, if you perform that kind of time measurement, be sure to write instead:
RmvTime((QElemPtr)&theTMTask); remaining = theTMTask.tmCount; theTMTask.tmReserved = 0; InsXTime((QElemPtr)&theTMTask); PrimeTime((QElemPtr)&theTMTask, 0);Since the Time Manager, prior to System Software 7.1, doesn't care about tmReserved, then you can set tmReserved to 0 before each call to InsXTime without checking the system version. You still have, of course, to ensure that the Time Manager you're using is the extended one (gestaltTimeMgrVersion 'tmgr', answering gestaltExtendedTimeMgr (= 3)), and, at this point, there is no way to tell what's going to happen under Mac OS 8.
This section describes an optimization that you might want to employ when using the Time Manager in the presence of virtual memory (VM). Most developers will not be interested in this; however, all users of the Time Manager should heed the following warning.
qLink
field in the TMTask before installing it.
As described in Inside Macintosh: Memory, Time Manager tasks are automatically deferred by the Virtual Memory (VM) system to avoid double page faults. This was done for backward compatibility with existing applications that use the Time Manager, but it can seriously increase the latency between when the timer expires and when your Time Manager task executes.
For more information about interactions between the Time Manager and VM, see Technote 1094, "Virtual Memory Application Compatibility".
For example, if you set a Time Manager task to execute at time X and, at time (X - delta) some process takes a page fault, your Time Manager task will not be called until time (X + Y - delta), where Y is the time required to field a page fault. If the page fault causes the hard disk to seek, Y could be as great as the hard disk's average seek time, approximately 10ms. If you are trying to use the Time Manager to measure time in microseconds, this could be a problem.
There is a way you can install Time Manager tasks so the callback is not deferred by VM; however, before using this technique, you should be aware of the dangers. Because VM does not defer these special Time Manager tasks, it is possible for them to fire when paging is not safe. To avoid fatal page faults, you must ensure:
HoldMemory(&theTask, sizeof(TMTask));
// Ensure the code doesn't move in logical memory HLock(ttaskCodeHandle); // Ensure the code is held in physical memory and cannot be paged to disk HoldMemory(*ttaskCodeHandle, GetResourceSizeOnDisk(ttaskCodeHandle));
If you call InsTime or InsXTime with the qLink field set to $65616461, the VM patch on the Time Manager will recognize your special requirements and execute your timer task as soon as it fires, regardless of whether paging is safe or not.
pascal void Microseconds(UnsignedWide *microseconds);
Thanks to Brian Bechtel, Drew Colace, Denis G. Pelli and Bob Wambaugh.